#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
#include <string>
#include "ThreadPool.h"

// 测试任务: 无返回值
void TestReturnVoid(int i)
{
    std::cout << "void task: " + std::to_string(i) << " end execute! " << std::endl;
}
// 测试任务: 返回值为 string
std::string TestReturnString(std::string& str, int i)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    return "string " + str + " get num: " + std::to_string(i);
}
// 测试任务: 返回值为 int
int TestReturnInt(int n)
{
    if(n == 1) return 1;
    else if(n == 2) return 1;

    return TestReturnInt(n-1)+TestReturnInt(n-2);
}

int main()
{
    std::cout << "============= 线程池测试 3 =============" << std::endl;

    try
    {
        // 一.创建线程数
        size_t threadCount = std::thread::hardware_concurrency();
        threadCount = threadCount == 0 ? 1 : threadCount;
        size_t poolThreads = std::min(threadCount, (size_t)4);
        
        std::cout << "系统有 " << threadCount << " 个CPU核心" << std::endl;
        std::cout << "创建拥有 " << poolThreads << " 个线程的线程池" << std::endl;

        // 二.创建线程 以及保存future对象的容器
        ThreadPool threadpool(threadCount);

        std::cout << "创建线程池成功" << std::endl;

        std::vector<std::future<void>> voidResults;
        std::vector<std::future<std::string>> stringResults;
        std::vector<std::future<int>> intResults;

        std::cout << "创建保存 future<void> 对象的容器成功       " << std::endl;
        std::cout << "创建保存 future<std::string> 对象的容器成功" << std::endl;
        std::cout << "创建保存 future<int> 对象的容器成功        " << std::endl;
        std::cout << std::endl;


        // 三.提交任务
        // 1.提交返回值为 void 的任务
        std::cout << "============= 开始提交任务 =============" << std::endl;
        for(int i = 1; i < 6; i++)
        {
            voidResults.emplace_back(threadpool.enqueue(TestReturnVoid, i));
            std::cout << "提交的任务为: void TestReturnVoid(int, " << i << ")" << std::endl;
        }
        
        // 3.提交返回值为 string 的任务
        for(int i = 1; i < 6; i++)
        {
            std::string str("task"+std::to_string(i));
            stringResults.emplace_back(threadpool.enqueue(TestReturnString, str, i));
            std::cout << "提交的任务为: std::string TestReturnString(std::string& str, " << i << ")" << std::endl;

        }
        // 3.提交返回值为 int 类型的任务
        for(int i = 1; i < 6; i++)
        {
            intResults.emplace_back(threadpool.enqueue(TestReturnInt, i));
            std::cout << "提交的任务为: int TestReturnInt(int " << i << ")" << std::endl;
        }
        std::cout << std::endl;

        // 四.获取结果
        // 1.获取返回值为void类型的结果
        std::cout << "====== 开始异步获取任务执行的结果 ======" << std::endl;
        for(auto& future : voidResults)
        {
            /**
             * 当异步任务无返回值时，使用 std::future<void>。
             * 主要功能是 同步等待任务完成 和 异常传递，而非获取结果。
             * 务必调用 get() 或 wait() 确保任务正确同步和异常处理。
             * 
             * 无返回值的情况下：wait()和get()的作用是否相同？
             * 在 std::future<void>（即任务无返回值）的情况下，wait() 和 get() 的核心作用类似，但仍有关键区别.
             * 1. 相同点:
             * 同步等待两者都会阻塞当前线程，直到任务完成（包括正常结束或抛出异常）。
             * 共享状态依赖：都要求 future 关联的共享状态有效（即未调用过 get() 或未移动 future）。
             * 2. 关键区别
             *    行为	        wait()	                    get()
             *   返回值	         无	                     无（返回 void）
             * 异常处理	 不检查异常, 任务异常被忽略	     若任务抛出异常，会重新抛出该异常
             * 调用次数	 可多次调用	                    只能调用一次（调用后 future 无效）
             * 典型用途	 仅等待任务完成	                等待任务完成 + 检查异常
             */
            future.wait();
        }

        // 2.获取返回值为string类型的结果
        for(auto& future : stringResults)
        {
            std::cout << future.get() << std::endl;
        }
        std::cout << std::endl;

        // 3.获取返回值为int类型的结果
        for(size_t i = 1; i <= intResults.size(); ++i)
        {
            std::cout << i << "的斐波那契数为: " << intResults[i-1].get() << std::endl;
        }

        std::cout << std::endl;

        std::cout << "================= 测试完成 =================" << std::endl;
        std::cout << "所有任务完成！线程池功能正常" << std::endl;
        
        // 测试线程池状态
        std::cout << "线程池是否已停止: " << (threadpool.isStopped() ? "是" : "否") << std::endl;

    }
    catch(const std::exception& e)
    {
        std::cerr << "线程池出现异常: " << e.what() << '\n';
        return 1;
    }
    

    return 0;
}